package io.gitee.bluemiaomiao.dataanalyzebackend.config;

import com.alibaba.fastjson.JSON;
import io.gitee.bluemiaomiao.dataanalyzebackend.domian.Ruser;
import io.gitee.bluemiaomiao.dataanalyzebackend.service.RuserService;
import io.gitee.bluemiaomiao.dataanalyzebackend.util.ResultCodeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

/**
 * @Author: TLang @Date: 2020/11/6
 *
 * @description: 配置角色权限
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired RuserService ruserService;
  @Autowired UserService userService;
  @Autowired UrlAccessDecisionManager urlAccessDecisionManager;
  @Autowired UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(10);
  }

  @Override
  public void configure(AuthenticationManagerBuilder auth) throws Exception {
    // 使用自定义登录身份认证组件FilterlnvocationSecurityMetadataSource
    auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    ;
    //        auth.authenticationProvider(new JwtAuthenticationProvider(userDetailsService));
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
        .withObjectPostProcessor(
            new ObjectPostProcessor<FilterSecurityInterceptor>() {
              @Override
              public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                o.setAccessDecisionManager(urlAccessDecisionManager);
                o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);
                return o;
              }
            })
        .antMatchers("/Test/cs")
        .permitAll()
        .and()
        .formLogin()
        .successHandler(
            new AuthenticationSuccessHandler() {
              @Override
              public void onAuthenticationSuccess(
                  HttpServletRequest httpServletRequest,
                  HttpServletResponse httpServletResponse,
                  Authentication authentication)
                  throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter out = httpServletResponse.getWriter();
                Ruser ruser =
                    (Ruser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                String s = null;
                s = JSON.toJSON(ResultCodeUtil.success(ruser)).toString();
                out.write(s);
                out.flush();
                out.close();
              }
            })
        .failureHandler(
            new AuthenticationFailureHandler() {
              @Override
              public void onAuthenticationFailure(
                  HttpServletRequest httpServletRequest,
                  HttpServletResponse httpServletResponse,
                  AuthenticationException e)
                  throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter out = httpServletResponse.getWriter();
                String s = null;
                s = JSON.toJSON(ResultCodeUtil.failed()).toString();
                out.write(s);
                out.flush();
                out.close();
              }
            })
        .permitAll()
        .and()
        .logout()
        .logoutSuccessHandler(
            new LogoutSuccessHandler() {
              @Override
              public void onLogoutSuccess(
                  HttpServletRequest httpServletRequest,
                  HttpServletResponse resp,
                  Authentication authentication)
                  throws IOException, ServletException {
                resp.setContentType("application/json;charset=utf-8");
                PrintWriter out = resp.getWriter();
                ResultCodeUtil.success(null, "登出成功");
                String s = JSON.toJSONString(ResultCodeUtil.success(null, "登出成功")).toString();
                out.write(s);
                out.flush();
                out.close();
              }
            })
        .permitAll()
        .and()
        .csrf()
        .disable()
        .exceptionHandling()
        .authenticationEntryPoint(
            new AuthenticationEntryPoint() {
              @Override
              public void commence(
                  HttpServletRequest req,
                  HttpServletResponse resp,
                  AuthenticationException authException)
                  throws IOException, ServletException {
                resp.setContentType("application/json;charset=utf-8");
                PrintWriter out = resp.getWriter();
                String s = null;
                if (authException instanceof InsufficientAuthenticationException) {
                  ResultCodeUtil.unauthorized(null);
                  s = JSON.toJSON(ResultCodeUtil.unauthorized(null)).toString();
                }
                out.write(s);
                out.flush();
                out.close();
              }
            })
        .accessDeniedHandler(
            new AccessDeniedHandler() {
              @Override
              public void handle(
                  HttpServletRequest httpServletRequest,
                  HttpServletResponse httpServletResponse,
                  AccessDeniedException e)
                  throws IOException, ServletException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter out = httpServletResponse.getWriter();
                String s = null;
                s = JSON.toJSON(ResultCodeUtil.unauthorized(null)).toString();
                out.write(s);
                out.flush();
                out.close();
              }
            });
    http.cors();
  }

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    // 配置那些域可以跨站请求资源
    configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
    // 配置支持的方法
    configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
    configuration.applyPermitDefaultValues();
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
  }
}
